package plgutils

import (
	"bytes"
	"dgo/MyProj/PrjHttpUtils"
	"dgo/goutils/utils"
	"fmt"
	"gitee.com/ymofen/supervalue"
	"regexp"
	"sync"
	"time"
)

type objMatchItem struct {
	matchVal string
	regex    *regexp.Regexp
	data     string
}

type ObjMatchPlg struct {
	PlgBase
	lk          sync.RWMutex
	lst         []*objMatchItem
	msglst      *utils.SyncCycleList
	filename    string
	rowSep      string
	lastFileBuf []byte
}

func (this *ObjMatchPlg) reload() {
	if len(this.filename) > 0 {
		this.reloadFromFile()
	}
}

func (this *ObjMatchPlg) reloadBuf(dataBuf []byte) {
	if bytes.Compare(this.lastFileBuf, dataBuf) == 0 {
		return
	}

	this.lk.Lock()
	defer this.lk.Unlock()
	lst := make([]*objMatchItem, 0, 1024)

	r := bytes.NewReader(dataBuf)
	utils.ReadPerLineEx(r, func(idx int64, line []byte) bool {
		str := string(line)
		if len(str) > 0 {
			if len(str) >= 2 && str[0] == '#' && str[1] == ' ' { // 注释
				return true
			}
			s1, s2 := utils.Split2Str(str, this.rowSep)
			itm := &objMatchItem{}
			itm.matchVal = s1
			itm.regex, _ = regexp.Compile(s1)
			itm.data = s2
			lst = append(lst, itm)
		}
		return true
	})
	this.lst = lst
}

func (this *ObjMatchPlg) reloadFromFile() {
	buf, err := utils.ReadFile(this.filename)
	if err != nil {
		return
	}

	this.reloadBuf(buf)

}

/*
			{
				  "id": "ntripclt",
				  "type": "utils.obj.match",
				  "conf": {
			          "file":"conf/user-bypass.conf",
	                  "srcText":"",
		              "row-sep":" "
				  }
				}
*/
func (this *ObjMatchPlg) ReloadConf(conf *wrapper.SuperValue) error {
	if conf == nil {
		return nil
	}

	if this.msglst == nil {
		this.msglst = utils.NewSyncCycleList()
	}

	this.rowSep = conf.StringByName("row-sep", " ")
	this.filename = conf.StringByPath("file", "")
	this.reload()
	conf.CheckExistsStrFunc("srcText", func(strv string) {
		this.reloadBuf([]byte(strv))
	})

	utils.DefaultPatrolTask().AddTask(this.PlugId, time.Second*30, func(id interface{}, args ...interface{}) {
		utils.DefaultWorkers().PostTaskFunc(this.PlugId, this.reload)
	})
	return nil
}

func (this *ObjMatchPlg) Close() (err error) {
	this.PlgBase.Close()
	utils.DefaultPatrolTask().DelTask(this.PlugId)
	return
}

func (this *ObjMatchPlg) GetValue(itype int, args ...interface{}) (rval interface{}) {
	if itype == 0 || itype == 10 {
		val := utils.GetStrValue(utils.CheckGetValInlst(args, 0, ""), "")
		if len(val) == 0 {
			return fmt.Errorf("非法参数")
		}
		this.lk.RLock()
		defer this.lk.RUnlock()
		for i := 0; i < len(this.lst); i++ {
			itm := this.lst[i]
			regex := itm.regex
			if regex == nil {
				if itm.matchVal == val {
					return itm.data
				}
			} else {
				if regex.FindString(val) == val {
					return itm.data
				}
			}
		}
		return ""
	} else {
		return fmt.Errorf("非法的itype:%d", itype)
	}

}

func (this *ObjMatchPlg) DoStatusRequestRequest(args ...interface{}) (resp interface{}) {
	json, _ := NewSVArgs(false, args...)

	if json != nil {
		itype := json.IntByName("type", 0)
		if itype == 99 {
			json := wrapper.NewSVObject()
			json.SetKeyValues("now", utils.NowString())
			json.SetKeyValue("object-cnt", len(this.lst))
			return json
		} else if itype == 98 {
			return this.msglst
		} else if itype == 95 {
			this.reload()
			return utils.BuildJSONString("code", 0, "cnt", len(this.lst))
		} else if itype == 1 {
			json := wrapper.NewSVArray()
			this.lk.RLock()
			defer this.lk.RUnlock()
			for i := 0; i < len(this.lst); i++ {
				itm := this.lst[i]
				rec := json.AppendObject()
				rec.SetKeyValue("match", itm.matchVal)
				rec.SetKeyValue("data", itm.data)
			}

			return json

		} else {
			//resp = this.DoRequest(args...)
			//if resp != nil {
			//	return resp
			//}
		}
	}
	var sb utils.BytesBuilder
	PrjHttpUtils.AppendIndexBody(&sb, "status", "status?type=99")
	PrjHttpUtils.AppendIndexBody(&sb, "msglist", "status?type=98&n=100&searchval=")
	PrjHttpUtils.AppendIndexBody(&sb, "reload", "status?type=95")
	PrjHttpUtils.AppendIndexBody(&sb, "lst", "status?type=1&n=100&searchval=")
	return sb.Bytes()

}

func (this *ObjMatchPlg) LogInfoMessage(s string, args ...interface{}) {
	this.msglst.LogMsg(s, args...)
	utils.Log.Msgf(this.PlugId, utils.LogLV_INFO, 1, s, args...)
}

func (this *ObjMatchPlg) LogWarnMessage(s string, args ...interface{}) {
	this.msglst.LogMsg(s, args...)
	utils.Log.Msgf(this.PlugId, utils.LogLV_WARN, 1, s, args...)
}

func CreateObjMatchPlgFunc(args ...interface{}) (rval interface{}, err error) {
	obj := &ObjMatchPlg{}

	if len(args) > 0 {
		if str, ok := args[0].(string); ok {
			obj.PlugId = str
		}
	}
	rval = obj
	return
}
